//rastrigin problem-depended class
//$Id: rastrigin.h 441 2010-04-09 17:27:20Z Oleg.Bulychov $
#pragma once

#include "src/heo/include/lf_endl.h"
#include "src/heo/include/random.h"
#include "src/heo/include/reflection.h"
#include "src/heo/include/solution.h"
#include "src/heo/include/transmit_vector.h"
#include "src/heo/include/optimization_direction.h"

struct Rastrigin_Config
{
    size_t      limit_output_;
    int         precision_;

    static char const* get_Name() { return "rastrigin"; }

    template<class V>
    void accept(V& v)
    {
         v(VAR_(limit_output),               10);
         v(VAR_(precision),                   6);
    }
};
//__________________________________________________________________________________
struct Rastrigin_Problem
{
    size_t n_;
    int a_;
    double lbound_;
    double rbound_;

    explicit Rastrigin_Problem(): n_(0), a_(0), lbound_(0), rbound_(0)
    {}

    static char const* get_Default_File_Name() { return "rastrigin_50_10.txt"; }

    template<class I, class E>
    bool read(I& in, E* env, uniform_random& rnd)
    {
        in >> n_ >> a_ >> lbound_ >> rbound_;
        if (n_<=0 || a_<=0 || lbound_>=rbound_)
            return false;
        return true;
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________
class Rastrigin_Solution
{
    //DISALLOW_COPY_AND_ASSIGN(Rastrigin_Solution);
public:
    typedef double                  TCostType;
    typedef minimization<TCostType> TDirection;
protected:
    TCostType           cost_;
    bool                changed_;
    std::vector<double> data_;
public:
    explicit Rastrigin_Solution(): cost_(0), changed_(false)
    {}

    template<class E>
    void init(E* env, uniform_random& rnd)
    {
        data_.resize(env->problem_.n_);
    }

    template<class V>
    void accept(V& v)
    {
        v(cost_);
        v(changed_);
        v(data_);
    }

    void write(std::string const& file_name)
    {
    }

    template<class E>
    void generate(E* env, uniform_random& rnd)
    {
        for (size_t i = 0; i < env->problem_.n_; ++i)
        {
            data_[i] = env->problem_.lbound_+(env->problem_.rbound_-env->problem_.lbound_)*rnd.next_Double();
        }
        changed_ = true;
    }

    TCostType get_Cost() const
    {
        ASSERT_(!changed_);
        return cost_;
    }

    template<class E>
    void evaluate(E* env, uniform_random& rnd)
    {
        if (!changed_)
            return;

        //:Rastrigin
        cost_ = double(env->problem_.n_)*env->problem_.a_;
        for (size_t i = 0; i < env->problem_.n_; ++i)
        {
            cost_ += data_[i]*data_[i]-env->problem_.a_*cos(2.*Math_PI*data_[i]); // x[i]^2-a*cos(2*pi*x[i])
        }

        //:Rosenbrock
        //cost_ = 0;
        //for (size_t i = 0; i < env->problem_.n_ - 1; ++i)
        //{
        //    cost_ += 100*(data_[i + 1] - data_[i]*data_[i])*
        //                 (data_[i + 1] - data_[i]*data_[i]) + 
        //                 (data_[i]- 1) * (data_[i]- 1);
        //}

        changed_ = false;
    }

    void assign(Rastrigin_Solution const& sol)
    {
        changed_ = sol.changed_;
        cost_    = sol.cost_;
        data_    = sol.data_;
    }

    template<class X>
    void copy_To(X& x) const
    {
        x.assign(*this);
    }

    template<class E>
    void print(std::ostream& os, E* env)
    {
        double d = 0;
        for (size_t i = 0; i < env->problem_.n_; ++i)
        {
            d += (1 - data_[i]) * (1 - data_[i]);
        }
        for (size_t i = 0; i < env->problem_.n_; ++i)
        {
            os.precision(env->cfg_.precision_);
            os << std::fixed << data_[i] << " ";
            if (i > env->cfg_.limit_output_)
            {
                os << "...";
                break;
            }
        }
        os << lf
            << "cost: " << std::fixed << get_Cost() << lf
            << "residual: " << d << lf;
    }

    template<class E>
    static bool read(E* env, std::string const& file_name, Solution_Pool<Rastrigin_Solution>& pool)
    {
        return false;
    }

    template<class E>
    void write(E* env, std::string const& file_name, size_t id, size_t count)
    {
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________

//EOF!
